# -*- coding: utf-8 -*-

import logging
import time
import threading
import simplejson
import httplib, urllib
import hashlib

import openerp
from openerp.http import request
from openerp.osv import osv, fields
from openerp.api import Environment
from contextlib import closing


CTI_REQUEST_INTERVAL = 2
_logger = logging.getLogger(__name__)

## ------------------------
## 呼叫中心坐席设置
## ------------------------
class dzx_callcenter_extension(osv.Model):
    """ 呼叫中心分机坐席."""
    _name = 'dzx_callcenter.extension'

    _columns = {
        'user_id': fields.many2one('res.users','User'),
        #对应SIP软件中的坐席号
        'cc_user': fields.char(u'呼叫中心用户登录id'),
        #对应SIP软件中的用户名
        'cc_extno': fields.char(u'分机号'),
        #暂时无用
        'cc_password': fields.char(u'呼叫中心用户登录密码'),
        'cc_callee': fields.char(u'拨号方法'),
        'cc_dn': fields.char(u'坐席归属'),
        'user_active':fields.related('user_id','active',string=u'用户是否启用',type='boolean',readonly='1'),
    }
    _sql_constraints = [('unique_user_id', 'unique(user_id)', u'用户id唯一')]


#----------------------------------------------------------
# Controllers
#----------------------------------------------------------
class Controller(openerp.addons.bus.bus.Controller):
    users_last_return = {}
    users_last_poll = {}
    users_threads = {}

    def __init__(self):
        self.cti_server_ip = openerp.tools.config.get('cti_server_ip')
        self.cti_server_port = openerp.tools.config.get('cti_server_port')

    #呼叫中心在线用户后台刷新状态线程运行函数
    def loop(self, registry, uid, act_data, context=None):
        interval = int(time.time()) - self.users_last_poll[uid]
        #如果用户浏览器关闭了一分钟，则认为超时了，结束线程loop
        while interval <= 60:
            #try:
            if self.users_last_return.has_key(uid):
                with Environment.manage():
                    with closing(registry.cursor()) as cr:
                        extensions = registry['dzx_callcenter.extension'].search_read(cr, openerp.SUPERUSER_ID,
                                                                        [('user_id', '=', uid)])
                        if extensions:
                            extension = extensions[0]
                            act_data = {'act': 'query', 'User': extension['cc_user']}
                            self.request(registry, uid, act_data, context)
            else:
                self.request(registry, uid, act_data, context)
            time.sleep(CTI_REQUEST_INTERVAL)
            # except Exception, e:
            #     _logger.exception("callcenter.loop error, sleep and retry")
            #     time.sleep(5)
            interval = int(time.time()) - self.users_last_poll[uid]
        else:
            #用户关闭浏览器后，删除用户最后呼叫中心返回状态信息，便于重新打开网页后init能重新执行
            if self.users_last_return.has_key(uid):
                del self.users_last_return[uid]
                del self.users_threads[uid]

    #向CTI服务器http请求
    def request(self, registry, uid, act_data, context=None):
        with Environment.manage():
            http_client = None
            result_data = {}
            try:
                params = urllib.urlencode(act_data)

                headers = {"Content-type": "application/x-www-form-urlencoded"
                    , "Accept": "text/plain"}
                http_client = httplib.HTTPConnection(self.cti_server_ip, self.cti_server_port, timeout=5)
                http_client.request("POST", "/operurl.php", params, headers)

                response = http_client.getresponse()
                if response.status == 200 or response.reason == 'OK':
                    data_string = response.read()
                    data_split = data_string.split(' ')
                    other_items = []
                    for item in data_split:
                        item_split = item.split('=')
                        if len(item_split) == 2:
                            result_data[item_split[0]] = item_split[1]
                        else:
                            other_items.append(item)
                    if other_items:
                        result_data['prompt'] = ' '.join(other_items)

            except Exception, e:
                _logger.exception("callcenter.loop error, sleep and retry: %s", e)
                time.sleep(5)

            finally:
                if http_client:
                    http_client.close()
            changed = False
            if self.users_last_return.has_key(uid):
                if cmp(self.users_last_return[uid], result_data) != 0:
                    changed = True
            #else:
            #    changed = True
            self.users_last_return[uid] = result_data
            #如果CTI服务器返回的用户状态信息有变化或者用户手动操作变更签入或在线状态，则通知客户端浏览器
            if changed or act_data['act'] != 'query':
                with closing(registry.cursor()) as cr:
                    #uid是当前用户，发送给自己
                    channel = (cr.dbname, 'callcenter.extension', uid)
                    act_data['return'] = result_data
                    _logger.info('------ cti request act_data: %s' % act_data)
                    registry['bus.bus'].sendone(cr, uid, channel, act_data)
        return result_data

    def _poll(self, dbname, channels, last, options):
        if request.session.uid:
            registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
            #channels.append((request.db, 'callcenter.presence'))
            channels.append((request.db, 'callcenter.extension', request.uid))
            self.users_last_poll[uid] = int(time.time())
            if not self.users_threads.has_key(uid):
                self.init()
        return super(Controller, self)._poll(dbname, channels, last, options)

    #呼叫中心坐席初始化登录
    @openerp.http.route('/callcenter/init', type="json", auth="user")
    def init(self):
        extension = {}
        registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
        extensions = registry['dzx_callcenter.extension'].search_read(cr, 1, [('user_id', '=', uid)])
        if extensions:
            extension = extensions[0]
            #用户登录时尝试登录呼叫中心坐席
            if extension:
                self.users_last_poll[uid] = int(time.time())
                #如果用户不存在后台刷新线程，则开启一个线程
                if not self.users_last_return.has_key(uid):
                    act_data = {'act': 'login', 'User': extension['cc_user'], 'extno': extension['cc_extno']}
                    #bus_bus = registry['bus.bus']
                    if self.cti_server_ip and self.cti_server_port:
                        threaded_calculation = threading.Thread(target=self.loop, args=(registry, uid, act_data, context))
                        self.users_threads[uid] = threaded_calculation
                        threaded_calculation.daemon = True
                        threaded_calculation.start()
                #用户还没有关闭浏览器超时，重新打开浏览器，则发送CTI最新的状态信息给用户浏览器
                else:
                    act_data = {'act': 'login', 'User': extension['cc_user'], 'extno': extension['cc_extno'],
                                'return': self.users_last_return[uid]}
                    channel = (cr.dbname, 'callcenter.extension', uid)
                    registry['bus.bus'].sendone(cr, uid, channel, act_data)
        return extension

    @openerp.http.route('/callcenter/post', type="json", auth="user")
    def post(self, act_data):
        registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
        #bus_bus = registry['bus.bus']
        if self.cti_server_ip and self.cti_server_port:
            threaded_calculation = threading.Thread(target=self.request, args=(registry, uid, act_data, context))
            threaded_calculation.start()
            return 'OK'
        else:
            return ''
